//
// Created by martin on 2/17/22.
//

#include "EventLoopThreadPool.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/EventLoopThread.h"

#include <assert.h>

using namespace muduo;
using namespace muduo::net;

EventLoopThreadPool::EventLoopThreadPool(EventLoop *baseLoop, const std::string &nameArg)
: baseLoop_(baseLoop), // 指向基础的EventLoop对象
name_(nameArg),        // 线程池名称
started_(false),       // 启动状态
numThreads_(0),        // 线程数量
next_(0)               // 下一个EventLoopThread位于threads_数组中的下标
{
}

EventLoopThreadPool::~EventLoopThreadPool()
{
    // Don't delete loop, it's stack variable
}

/**
 * 启动IO线程池.
 * 只能启动一次, 而且必须是baseLoop_的创建线程调用start().
 * @param cb 线程函数初始回调
 */
void EventLoopThreadPool::start(const ThreadInitCallback &cb)
{
    assert(!started_); // 防止重复启动线程池
    baseLoop_->assertInLoopThread(); // 断言baseLoop_对象创建者是线程池的start()调用者

    started_ = true; // 标记线程池已启动

    // 根据用户指定线程数, 创建IO线程组
    /* create numThreads_ EventLoopThread, added to threads_ */
    for (int i = 0; i < numThreads_; ++i) { // 线程编号范围取决于用户指定的线程数
        char buf[name_.size() + 32];
        snprintf(buf, sizeof(buf), "%s%d", name_.c_str(), i); // IO线程名称: 线程池名称 + 线程编号
        EventLoopThread* t = new EventLoopThread(cb, buf);
        threads_.push_back(std::unique_ptr<EventLoopThread>(t)); // 将EventLoopThread对象指针 插入threads_数组
        loops_.push_back(t->startLoop()); // 启动IO线程, 并将线程函数创建的EventLoop对象地址 插入loops_数组
    }
    if (numThreads_ == 0 && cb)
    { // 如果没有创建任何线程, 也会调用回调cb; 否则, 会在新建的线程函数初始化完成后(进入loop循环前)调用
        cb(baseLoop_);
    }
}

/**
 * 从线程池获取下一个event loop
 * @note 默认event loop是baseLoop_ (创建baseLoop_线程, 通常也是创建线程池的线程).
 * 没有调用setThreadNum()设置numThreads_(number of threads)时, numThreads_默认为０,
 * 所有IO操作都默认交由baseLoop_的event loop来完成, 因为没有其他IO线程.
 */
EventLoop* EventLoopThreadPool::getNextLoop()
{
    baseLoop_->assertInLoopThread();
    assert(started_);
    EventLoop* loop = baseLoop_;

    // 如果loops_为空, 则loop指向baseLoop
    // 如果非空, 则按round-robin(RR, 轮叫)的调度方式(从loops_列表中)选择一个EventLoop
    if (!loops_.empty())
    {
        // round-robin
        loop = loops_[next_];
        ++next_;
        if (implicit_cast<size_t>(next_) >= loops_.size())
        {
            next_ = 0;
        }
    }
    return loop;
}

EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode)
{
    baseLoop_->assertInLoopThread();
    EventLoop* loop = baseLoop_;

    if (!loops_.empty())
    {
        loop = loops_[hashCode % loops_.size()];
    }
    return loop;
}

std::vector<EventLoop*> EventLoopThreadPool::getAllLoops()
{
    baseLoop_->assertInLoopThread();
    assert(started_);

    if (loops_.empty())
    {
        return std::vector<EventLoop*>(1, baseLoop_);
    }
    else
    {
        return loops_;
    }
}

